package ch01

import (
	"encoding/json"
	"fmt"
	"os"
	"reflect"
	"strings"
	"text/template"
)

type Person struct {
	Name    string   `json:"name"`
	Age     int      `json:"age"`
	Email   string   `json:"email"`
	Hobbies []string `json:"hobbies"`
}

var templateString = `
CREATE TABLE {{.TableName}} (
{{range .Columns}}    {{.Name}} {{.Type}},
{{end}}    PRIMARY KEY (` + "`id`" + `)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
`

type Column struct {
	Name string
	Type string
}

type TemplateData struct {
	TableName string
	Columns   []Column
}

func json2sql() {
	jsonString := `{
        "name": "Alice",
        "age": 30,
        "email": "alice@example.com",
        "hobbies": ["reading", "traveling"]
    }`

	var person Person
	err := json.Unmarshal([]byte(jsonString), &person)
	if err != nil {
		fmt.Println("Error parsing JSON:", err)
		return
	}

	tableName := "person"
	columns := []Column{}
	t := reflect.TypeOf(person)
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		name := field.Tag.Get("json")
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		typ := field.Type.String()
		columns = append(columns, Column{Name: name, Type: getMySQLType(typ)})
	}

	templateData := TemplateData{TableName: tableName, Columns: columns}

	tmpl, err := template.New("mysql").Parse(templateString)
	if err != nil {
		fmt.Println("Error parsing template:", err)
		return
	}

	err = tmpl.Execute(os.Stdout, templateData)
	if err != nil {
		fmt.Println("Error executing template:", err)
		return
	}
}

func getMySQLType(typ string) string {
	switch typ {
	case "string":
		return "VARCHAR(255)"
	case "int":
		return "INT"
	case "int8":
		return "TINYINT"
	case "int16":
		return "SMALLINT"
	case "int32":
		return "INT"
	case "int64":
		return "BIGINT"
	case "uint":
		return "INT UNSIGNED"
	case "uint8":
		return "TINYINT UNSIGNED"
	case "uint16":
		return "SMALLINT UNSIGNED"
	case "uint32":
		return "INT UNSIGNED"
	case "uint64":
		return "BIGINT UNSIGNED"
	case "float32":
		return "FLOAT"
	case "float64":
		return "DOUBLE"
	case "bool":
		return "BOOLEAN"
	case "[]string":
		return "TEXT"
	default:
		return "TEXT"
	}
}
